#include "Message_Processing.h"
extern uint16 UCD_TLV_Table[256];
void Init_UCD_TLV_TABLE()
{
	UCD_TLV_Table[18]  =L_UASB_TLV18    ; 
	UCD_TLV_Table[155] =L_SRCG_TLV155   ; 
	UCD_TLV_Table[156] =L_PB_TLV156     ; 
	UCD_TLV_Table[174] =L_MR_TLV174     ; 
	UCD_TLV_Table[190] =L_UPO_TLV190    ; 
	UCD_TLV_Table[191] =L_DPO_TLV191    ; 
	UCD_TLV_Table[192] =L_MINLPO_TLV192 ; 
	UCD_TLV_Table[193] =L_MAXLPO_TLV193 ; 
	UCD_TLV_Table[195] =L_IRI_TLV195    ; 
	UCD_TLV_Table[198] =L_IRANGBS_TLV198; 
	UCD_TLV_Table[199] =L_IRANGBE_TLV199; 
	UCD_TLV_Table[200] =L_BWREQBS_TLV200; 
    UCD_TLV_Table[201] =L_BWREQBE_TLV201; 
}

Msg_TLV *Get_UCD_TLV()
{
	Msg_TLV *p;
	p = (Msg_TLV *)malloc(sizeof(Msg_TLV));
	if(p == NULL)
	{
		printf("run out of memory");
		exit(1);
	}
	return(p);
}
 
void Append_UCD_TLV(Msg_TLV **ptr,uint16 type ,uint64 value)
{
	Msg_TLV *newnode;
	Msg_TLV *head;

	newnode        = Get_UCD_TLV();
	newnode->type  = type;
	newnode->len   = UCD_TLV_Table[type];//Global variable Table
	newnode->value = value;
	newnode->next  = NULL;
	head           = *ptr;
	if(*ptr == NULL)
	{
		newnode->next = NULL;
		*ptr = newnode;
	}
	else
	{
		while((*ptr)->next != NULL)
			*ptr  = (*ptr)->next;
		(*ptr)->next = newnode;
		(*ptr)       = head;
	}
}


void Init_Msg_UCD_TLV(Msg_TLV **ucd_tlv_pp)
{
	AppendTLV(ucd_tlv_pp, 190,UCD_TLV_Table,0x1);
	AppendTLV(ucd_tlv_pp, 191,UCD_TLV_Table,0x1);
	AppendTLV(ucd_tlv_pp, 192,UCD_TLV_Table,0x1);
	AppendTLV(ucd_tlv_pp, 193,UCD_TLV_Table,0x1);
	AppendTLV(ucd_tlv_pp, 195,UCD_TLV_Table,0x10);
	AppendTLV(ucd_tlv_pp, 198,UCD_TLV_Table,0x10); 
	AppendTLV(ucd_tlv_pp, 199,UCD_TLV_Table,0x10); 
	AppendTLV(ucd_tlv_pp, 200,UCD_TLV_Table,0x10); 
	AppendTLV(ucd_tlv_pp, 201,UCD_TLV_Table,0x10); 
}
void Init_UBP(Msg_BP **BP_pp)
{
	//intitial DIUC mapping to DL burst profile
	Append_Msg_BP(BP_pp,  1 , 1 );
	Append_Msg_BP(BP_pp,  2 , 2 );
	Append_Msg_BP(BP_pp,  3 , 3 );
	Append_Msg_BP(BP_pp,  4 , 4 );
	Append_Msg_BP(BP_pp,  5 , 5 );
	Append_Msg_BP(BP_pp,  6 , 6 );
	Append_Msg_BP(BP_pp,  7 , 7 );
	Append_Msg_BP(BP_pp,  8 , 8 );
	Append_Msg_BP(BP_pp,  9 , 9 );
	Append_Msg_BP(BP_pp, 10 ,10 );
	Append_Msg_BP(BP_pp, 11 ,11 );
	Append_Msg_BP(BP_pp, 12 ,12 );
}
void Acc_UCD_TLV(UCD *ucd)
{
	uint16 length=0;
	Msg_TLV *tmp_p;
	tmp_p = ucd->UCD_TLV_p;
	do{
	length = (uint16)(length+ucd->UCD_TLV_p->len);//indicate the value length
	length += 2; //including type and length bytes
	ucd->UCD_TLV_p = ucd->UCD_TLV_p->next;
	}while(ucd->UCD_TLV_p!=NULL);
	ucd->UCD_TLV_p = tmp_p;
	ucd->TLV_bytes = length ;
}
void Acc_UBP(UCD *UCD)
{
	uint16 num=0;
	Msg_BP *tmp_p;
	tmp_p = UCD->BProfile_p;
	do{
		num += 1;//including 
		UCD->BProfile_p = UCD->BProfile_p->next;
	}while(UCD->BProfile_p!=NULL);
	UCD->BProfile_p = tmp_p;
	UCD->BP_num = num ;
}

void Init_Msg_UCD(MMSG **MMsg_pp)
{
	(*MMsg_pp)      =(MMSG *)malloc(sizeof(MMSG));
	(*MMsg_pp)->ucd = (UCD *)calloc(sizeof(UCD),1);
	//Initail FCH Elements
	(*MMsg_pp)->ucd->MMType = 0x1;
	(*MMsg_pp)->ucd->CCC    = 0x2;
	(*MMsg_pp)->ucd->RangBOStart = 0x4;
	(*MMsg_pp)->ucd->RangBOEnd   = 0x4;
	(*MMsg_pp)->ucd->ReqBOStart  = 0x4;
	(*MMsg_pp)->ucd->ReqBOEnd    = 0x4;
	Init_Msg_UCD_TLV( &(*MMsg_pp)->ucd->UCD_TLV_p);
	Init_UBP(&(*MMsg_pp)->ucd->BProfile_p);
	Acc_UCD_TLV((*MMsg_pp)->ucd);
	Acc_UBP((*MMsg_pp)->ucd);
	
}
void Form_UCD_TLV(MsgQ **MsgPtr,UCD **ucd_pp)
{
	//Set the total bytes in TLV 
	Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->TLV_bytes,8);
	while((*ucd_pp)->UCD_TLV_p!=NULL)
	{
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->UCD_TLV_p->type,8);
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->UCD_TLV_p->len,8);
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->UCD_TLV_p->value,(uint8)(*ucd_pp)->UCD_TLV_p->len*8);
		(*ucd_pp)->UCD_TLV_p = (*ucd_pp)->UCD_TLV_p->next;
	}
}
void Form_UBP(MsgQ **MsgPtr,UCD **ucd_pp)
{
	//Set the total numbers in BP
	Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->BP_num,8);
	while((*ucd_pp)->BProfile_p!=NULL)
	{
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->BProfile_p->type,8);
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->BProfile_p->len ,8);
		Insert_MsgQ_DList(MsgPtr,0,4);//reserved
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->BProfile_p->DIUC,4);//DIUC
		Insert_MsgQ_DList(MsgPtr,(*ucd_pp)->BProfile_p->BurstProfile,8);//BP
		(*ucd_pp)->BProfile_p = (*ucd_pp)->BProfile_p->next;
	}
}
void Form_UCD(MMSG **mmsg_pp,MsgQ **MsgPtr)
{
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->MMType,L_MMTYPE_0);
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->CCC,L_CCC);
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->RangBOStart,L_RANGBOS);
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->RangBOEnd,L_RANGBOE);
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->ReqBOStart,L_REQBOS);
	Insert_MsgQ_DList(MsgPtr,(*mmsg_pp)->ucd->ReqBOEnd,L_REQBOE);
	Form_UCD_TLV(MsgPtr,&(*mmsg_pp)->ucd);
    Form_UBP(MsgPtr,&(*mmsg_pp)->ucd);

}
void DeForm_UCD_TLV(BUFFER **buf_pp,UCD **ucd_pp)
{
	uint64 type = 0;
	uint64 len  = 0;
	uint64 tlv_bytes =0;
    uint64 value= 0;
	
	DeFormat2Val(buf_pp,&tlv_bytes,8);
	PrintMsgVal("UCD","total TLV bytes",(uint32)tlv_bytes);
	(*ucd_pp)->TLV_bytes = (uint16 )tlv_bytes;
	while(tlv_bytes!=0)
	{
		DeFormat2Val(buf_pp,&type,8);
		DeFormat2Val(buf_pp,&len ,8);
		DeFormat2Val(buf_pp,&value,(uint8)len*8);
		AppendTLV(&(*ucd_pp)->UCD_TLV_p, (uint16)type,UCD_TLV_Table,value);
		(tlv_bytes) -= (len+2); //including type length and value 
		PrintMsgVal("UCD","type",(uint32)type);
		PrintMsgVal("UCD","len",(uint32)len);
		PrintMsgVal("UCD","value",(uint32)value);
	}
}
void DeForm_UBP(BUFFER **buf_pp,UCD **ucd_pp)
{
	uint64 tmp=0;
	Msg_BP *BP_p=NULL;
	uint64 BP_num =0;
	
	BP_p =(Msg_BP *)malloc(sizeof(Msg_BP));
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->BP_num,8);
	BP_num = (*ucd_pp)->BP_num;
	while(BP_num!=0)
	{
		DeFormat2Val(buf_pp,(uint64 *)&BP_p->type,8);//reserved
		DeFormat2Val(buf_pp,(uint64 *)&BP_p->len ,8);//reserved
		DeFormat2Val(buf_pp,&tmp ,4);//reserved
		DeFormat2Val(buf_pp,(uint64 *)&BP_p->DIUC,4);//DIUC
		DeFormat2Val(buf_pp,(uint64 *)&BP_p->BurstProfile, 8);//DL burst profile
		Append_Msg_BP(&(*ucd_pp)->BProfile_p,BP_p->DIUC ,BP_p->BurstProfile );
		BP_num -= 1; //including type length and value 
		PrintMsgVal("UCD","type",BP_p->type);
		PrintMsgVal("UCD","length",BP_p->len);
		PrintMsgVal("UCD","DIUC",BP_p->DIUC);
		PrintMsgVal("UCD","Burst Profile",BP_p->BurstProfile);
	}
}
void DeForm_UCD(BUFFER **buf_pp,UCD **ucd_pp)
{
	*ucd_pp = (UCD *)calloc(sizeof(UCD),1);
	//DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->MMType,L_MMTYPE_0);            
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->CCC,L_CCC);
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->RangBOStart,L_RANGBOS);
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->RangBOEnd,L_RANGBOE);
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->ReqBOStart,L_REQBOS);
	DeFormat2Val(buf_pp,(uint64 *)&(*ucd_pp)->ReqBOEnd,L_REQBOE);
	PrintMsg("----------","Decode UCD","----------");
	PrintMsgVal("UCD","CCC",(*ucd_pp)->CCC);
	PrintMsgVal("UCD","RangBOStart",(*ucd_pp)->RangBOStart);
	PrintMsgVal("UCD","RangBOEnd",(*ucd_pp)->RangBOEnd);
	PrintMsgVal("UCD","ReqBOStart",(*ucd_pp)->ReqBOStart);
	PrintMsgVal("UCD","ReqBOEnd",(*ucd_pp)->ReqBOEnd);
	DeForm_UCD_TLV(buf_pp,ucd_pp);
	DeForm_UBP(buf_pp,&*ucd_pp);
 }
void Compare_UCD(MMSG *mmsg_gen_p ,MMSG *mmsg_get_p)
{
	BUFFER *buf_gen_p=NULL;
	BUFFER *buf_get_p=NULL;
	MsgQ *Msg_gen_p=NULL;
	MsgQ *Msg_get_p=NULL;
	int result;

	Form_UCD(&mmsg_gen_p,&Msg_gen_p);
	buf_gen_p = FormatMsgQ2Buf(Msg_gen_p);

	Form_UCD(&mmsg_get_p,&Msg_get_p);
	buf_get_p = FormatMsgQ2Buf(Msg_get_p);
	result = memcmp (buf_get_p->buffer,buf_gen_p->buffer,buf_gen_p->bitoffset);
	printf("The compare result of UCD is %d\n",!result);

}
void Test_UCD()
{
	MsgQ *MsgPtr=NULL;
	MMSG *mmsg_gen_p=NULL;//generate
	MMSG *mmsg_ope_p=NULL;//operate
	MMSG *mmsg_get_p=NULL;//get
	BUFFER *buf_p=NULL;
	

    mmsg_get_p =(MMSG *)malloc(sizeof(MMSG));

	
	Init_MsgQ(&MsgPtr);
	Init_Buffer(&buf_p);

	Init_Msg_UCD(&mmsg_gen_p);
	Init_Msg_UCD(&mmsg_ope_p);    

	Form_UCD(&mmsg_ope_p,&MsgPtr);
	buf_p = FormatMsgQ2Buf(MsgPtr);
	buf_p->base =buf_p->buffer;
	buf_p->bitoffset=0;
	DeForm_UCD(&buf_p,&mmsg_get_p->ucd);
    Compare_UCD(mmsg_gen_p,mmsg_get_p);
}
